package org.snia.server.rs;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.DELETE;
import javax.ws.rs.Encoded;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.UriInfo;

import org.codehaus.jackson.JsonParseException;
import org.snia.cdmi.ErrorCodes;
import org.snia.cdmi.Headers;
import org.snia.cdmi.LinkSitePermission;
import org.snia.cdmi.exception.BadRequestException;
import org.snia.cdmi.model.AccessControlList;
import org.snia.cdmi.model.Container;
import org.snia.cdmi.model.ContainerProperties;
import org.snia.cdmi.model.Grantee;
import org.snia.cdmi.model.KeyGrantee;
import org.snia.cdmi.model.Permission;
import org.snia.cdmi.util.ParameterUtils;
import org.snia.server.dispatcher.Dispatcher;
import org.snia.server.dispatcher.DispatcherFactory;

@Path("/{container}")
@Encoded
public class ContainerResource extends AbstractResource {

	// 采用简单工厂方法 + 单例模式获得服务策略
	private final static Dispatcher compositor = DispatcherFactory.create();

	// private final static String[] SIGNED_PARAMETERS = { "acl", "metadata",
	// "task" };

	@Context
	private UriInfo ui;

	@PUT
	public Response putResource(@PathParam("container") String name,
			@Context HttpHeaders headers, byte[] context) {
		MultivaluedMap<String, String> params = ui.getQueryParameters();
		String option = params.getFirst("acl");
		if (option != null) {
			return this.setAccessControlPolicy(name, context);
		}
		option = params.getFirst("metadata");
		if (option != null) {
			return this.setUserMetadata(name, headers);
		}

		int maxnum = -1;
		String limit = null;
		Map<String, String> mapMeta = new HashMap<String, String>();

		for (String hdr : headers.getRequestHeaders().keySet()) {

			if (hdr.startsWith(Headers.CDMI_USER_METADATA_PREFIX)) {
				String meta = hdr.substring(
						Headers.CDMI_USER_METADATA_PREFIX.length(),
						hdr.length());
				mapMeta.put(meta, headers.getRequestHeader(hdr).get(0));
			}
			if (hdr.equals(Headers.CDMI_MAX_VERSION_NUM)) {
				maxnum = Integer.valueOf(headers.getRequestHeader(hdr).get(0));
			}
			if (hdr.equals(Headers.CDMI_LIMIT)) {
				limit = headers.getRequestHeader(hdr).get(0);
			}
		}
		return createContainer(name, maxnum, limit, mapMeta, context);
	}

	@GET
	public Response getResource(@PathParam("container") String name,
			@Context HttpHeaders headers, byte[] context) {
		MultivaluedMap<String, String> params = ui.getQueryParameters();
		String option = params.getFirst("acl");
		if (option != null) {
			return this.getAccessControlList(name);
		}
		option = params.getFirst("metadata");
		if (option != null) {
			return this.getUserMetadata(name);
		}
		option = params.getFirst("server");
		if (option != null) {
			// return this.getServer(name);
		}

		int maxnum = -1;
		String limit = null;
		Map<String, String> mapMeta = new HashMap<String, String>();

		for (String hdr : headers.getRequestHeaders().keySet()) {
			System.out.println(hdr + " - " + headers.getRequestHeader(hdr));
			// if (hdr.equals(Headers.CDMI_PREFIX)) {
			// String s_marker = params.getFirst("marker");
			// String s_maxresults = params.getFirst("maxresults");
			// int i_marker = (s_marker == null) ? 0 : Integer
			// .valueOf(s_marker);
			// int i_maxresults = (s_maxresults == null) ? 40 : Integer
			// .valueOf(s_maxresults);
			// return listObjects(name, headers.getRequestHeader(hdr).get(0),
			// i_marker, i_maxresults);
			// }
			if (hdr.equals(Headers.CDMI_LIMIT)) {
				limit = headers.getRequestHeader(hdr).get(0);
			}
		}
		return createContainer(name, maxnum, limit, mapMeta, context);
	}

	@DELETE
	public Response deleteResource(@PathParam("container") String name,
			@Context HttpHeaders headers, byte[] context) {
		return deleteContainer(name);
	}

	@HEAD
	public Response headResource(@PathParam("container") String name,
			@Context HttpHeaders headers, byte[] context) {
		MultivaluedMap<String, String> params = ui.getQueryParameters();
		String option = params.getFirst("metadata");
		if (option != null) {
			return this.getUserMetadata(name);
		}

		List<String> ls = headers
				.getRequestHeader(Headers.CDMI_REQUEST_METADATA);
		boolean withMetadata = false;
		if (ls != null && ls.size() > 0) {
			withMetadata = Boolean.valueOf(ls.get(0));
		}
		return getProperties(name, withMetadata);
	}

	/**
	 * 创建容器：PUT /mycontainer HTTP/1.1
	 * 
	 * @param name
	 * @param type
	 * @param site
	 * @param limit
	 * @param metadata
	 */

	@PUT
	private Response createContainer(
			@PathParam("container") String name,
			// @HeaderParam(Headers.CDMI_CLASS) String type,
			// @HeaderParam(Headers.CDMI_SITE) String site,
			@HeaderParam(Headers.CDMI_MAX_VERSION_NUM) int maxnum,
			@HeaderParam(Headers.CDMI_LIMIT) String limit,
			Map<String, String> mapMeta, byte[] context) {

		System.out.println("invoke::" + "createContainer");

		try {
			// 检查Container的格式是否正确
			ParameterUtils.validateContainerName(name);

			Container container = new Container();
			container.setName(name);
			container.setAccessKey(this.getPrincipal().getIdentifier());
			container.setCreationDate(new Date());
			// TODO 最大版本数量不能超过系统所设定的限制
			container.setMaxMumber4Version(maxnum);
			container.setPermission(LinkSitePermission.fromValue(limit));
			container.setUserMetadata(mapMeta);
			// 从body中获取数据填充Container对象
			container.fromJson(context);

			compositor.createContainer(container);
		} catch (IllegalArgumentException e) {
			throw new BadRequestException(ErrorCodes.InvalidArgument);

		} catch (JsonParseException e) {
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		} catch (IOException e) {
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		}

		return Response.ok().header(Headers.CDMI_VERSION, "1.0").build();
	}

	/**
	 * 删除容器：DELETE /mycontainer HTTP/1.1
	 * 
	 * @param name
	 */
	@DELETE
	private Response deleteContainer(@PathParam("container") String name) {

		System.out.println("invoke::" + "deleteContainer");
		// 检查Container的格式是否正确
		try {
			ParameterUtils.validateContainerName(name);
		} catch (IllegalArgumentException e) {
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		}
		
		// 1.检索分布式缓存，判断容器名是否存在，直接到4
		compositor.setAuthorization(this.getPrincipal());
		compositor.deleteContainer(name);
		return Response.ok().header(Headers.CDMI_VERSION, "1.0").build();
	}

	/**
	 * 获取容器访问控制策略：GET /mycontainer?acl HTTP/1.1
	 * 
	 * @param name
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	@PUT
	private Response setAccessControlPolicy(
			@PathParam("container") String name, byte[] acl) {

		System.out.println("invoke::" + "setAccessControlPolicy");

		try {
			// 检查Container的格式是否正确
			ParameterUtils.validateContainerName(name);
			
			Container container = new Container();
			// 从body中获取数据填充Container的ACL属性
			container.fromJson(acl);
			AccessControlList aclMap = container.getAccessControlList();
			// Map<String, Permission> acpMap = new HashMap<String ,
			// Permission>();
			// for (Map.Entry<String, String> m : aclMap.entrySet()) {
			// acpMap.put(m.getKey(), Permission.parsePermission(m.getValue()));
			// }

			compositor.setAccessControlPolicy(name, aclMap);
		} catch (IllegalArgumentException e) {
			throw new BadRequestException(ErrorCodes.InvalidArgument);
			
		} catch (JsonParseException e) {
			e.printStackTrace();
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		} catch (IOException e) {
			e.printStackTrace();
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		}

		return Response.ok().header(Headers.CDMI_VERSION, "1.0").build();
	}

	/**
	 * 获取容器访问控制策略：GET /mycontainer?acl HTTP/1.1
	 * 
	 * @param name
	 * @return
	 */
	@GET
	private Response getAccessControlList(@PathParam("container") String name) {

		System.out.println("invoke::" + "getAccessControlPolicy");
		// 检查Container的格式是否正确
		try {
			ParameterUtils.validateContainerName(name);
		} catch (IllegalArgumentException e) {
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		}
		
		Map<String, String> aclMap = compositor.getAccessControlList(name);
		AccessControlList acl = new AccessControlList();

		for (Map.Entry<String, String> m : aclMap.entrySet()) {
			Grantee accesskey = new KeyGrantee();
			accesskey.setIdentifier(m.getKey());
			acl.grantPermission(accesskey, Permission.fromValue(m.getValue()));
		}
		// TODO 目前只能是请求者自己
		acl.setAccessKey(this.getPrincipal().getIdentifier());
		String owner = this.getPrincipal().getIdentifier();
		String respStr = acl.toJson(owner);
		return Response.ok(respStr).header(Headers.CDMI_VERSION, "1.0").build();
	}

	/**
	 * 获取容器属性：HAED /mycontainer HTTP/1.1
	 * 
	 * @param name
	 * @param withMetadata
	 * @return
	 */
	@HEAD
	private Response getProperties(@PathParam("container") String name,
			@HeaderParam(Headers.CDMI_REQUEST_METADATA) boolean withMetadata) {

		System.out.println("invoke::" + "getProperties");

		// 检查Container的格式是否正确
		try {
			ParameterUtils.validateContainerName(name);
		} catch (IllegalArgumentException e) {
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		}
		
		ContainerProperties props = compositor
				.getProperties(name, withMetadata);
		Map<String, String> mapMeta = props.getUserMetadata();

		ResponseBuilder builder = Response.ok();
		for (Map.Entry<String, String> m : mapMeta.entrySet()) {
			builder.header(Headers.CDMI_USER_METADATA_PREFIX + m.getKey(),
					m.getValue());
		}
		return Response.ok().header(Headers.CDMI_VERSION, "1.0").build();
	}

	/**
	 * 设置容器元数据：PUT /mycontainer?metadata HTTP/1.1
	 * 
	 * @param name
	 * @param metadata
	 * @return
	 */
	@PUT
	private Response setUserMetadata(@PathParam("container") String name,
			@Context HttpHeaders metadata) {
		// 检查Container的格式是否正确
		try {
			ParameterUtils.validateContainerName(name);
		} catch (IllegalArgumentException e) {
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		}
		
		System.out.println("invoke::" + "setMetadata");
		Map<String, String> mapMeta = new HashMap<String, String>();
		for (String hdr : metadata.getRequestHeaders().keySet()) {
			System.out.println(hdr + " - " + metadata.getRequestHeader(hdr));
			if (hdr.startsWith(Headers.CDMI_USER_METADATA_PREFIX)) {
				String meta = hdr.substring(
						Headers.CDMI_USER_METADATA_PREFIX.length(),
						hdr.length());
				mapMeta.put(meta, metadata.getRequestHeader(hdr).get(0));
			}
		}

		if (mapMeta.size() != 0) {
			compositor.setUserMetadata(name, mapMeta);
		}

		return Response.ok().header(Headers.CDMI_VERSION, "1.0").build();
	}

	/**
	 * 获取容器元数据：GET/HEAD /mycontainer?metadata HTTP/1.1
	 * 
	 * @param name
	 * @return
	 */
	@GET
	@HEAD
	private Response getUserMetadata(@PathParam("container") String name) {

		System.out.println("invoke::" + "getMetadata");
		
		// 检查Container的格式是否正确
		try {
			ParameterUtils.validateContainerName(name);
		} catch (IllegalArgumentException e) {
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		}
		
		Map<String, String> mapMeta = compositor.getUserMetadata(name);
		ResponseBuilder builder = Response.ok();
		for (Map.Entry<String, String> m : mapMeta.entrySet()) {
			builder.header(Headers.CDMI_USER_METADATA_PREFIX + m.getKey(),
					m.getValue());
		}
		return builder.header(Headers.CDMI_VERSION, "1.0").build();
	}

	// /**
	// * 获得可用的存储服务：GET /mycontainer?server HTTP/1.1
	// *
	// * @param name
	// * @return
	// */
	// @GET
	// @Produces(MediaTypes.SERVER)
	// public Response getServer(@PathParam("container") String name) {
	//
	// System.out.println("invoke::" + "getServer");
	//
	// throw new UnsupportedOperationException(
	// "ContainerResource::getServer()");
	// }
	//
	// /**
	// * 列举具有相同服务前缀的对象：GET /mycontainer/?marker=value2&maxresults=value3
	// HTTP/1.1
	// *
	// * @param name
	// * @param prefix
	// * @param marker
	// * @param maxresults
	// * @return
	// */
	// @GET
	// @Produces("application/xml")
	// public Response listObjects(@PathParam("container") String name,
	// // @HeaderParam(Headers.CDMI_PREFIX) String prefix,
	// @QueryParam(QueryParameters.MARKER) int marker,
	// @QueryParam(QueryParameters.MAXRESULTS) int maxresults) {
	//
	// System.out.println("invoke::" + "listObjects");
	//
	// // 1.检索分布式缓存，判断容器名是否存在，如果存在直接到4
	//
	// // 2.如果不存在，检查Container的格式是否正确
	//
	// // 备注：检查数据库时，如果容器状态不是正常状态(如迁移中，删除中)，不允许获取数据。
	//
	// // 3.如果不正确直接返回错误
	//
	// // 4.如果容器名格式正确, 查询Object_Prefix表
	//
	// // 5.存在数据库错误，返回 NO DATA，系统记录错误日志。
	//
	// // 6.如果数据库操作正确，返回列表。
	//
	// throw new UnsupportedOperationException(
	// "ContainerResource::listObjects()");
	// }
	//
	// /***************************** 扩展:目录服务
	// *************************************/
	//
	// /**
	// * 列举具有相同服务前缀的对象：GET /mycontainer/?marker=value2&maxresults=value3
	// HTTP/1.1
	// *
	// * @param name
	// * @param dir
	// * @param type
	// * @param marker
	// * @param maxresults
	// * @return
	// */
	// @GET
	// @HeaderParam(Headers.CDMI_FILE_DIR)
	// @Produces("application/xml")
	// public Response listDirObjects(@PathParam("container") String name,
	// @HeaderParam(Headers.CDMI_FILE_DIR) String dir,
	// @HeaderParam(Headers.CDMI_FILE_VIEW) String type,
	// @QueryParam(QueryParameters.MARKER) int marker,
	// @QueryParam(QueryParameters.MAXRESULTS) int maxresults) {
	//
	// System.out.println("invoke::" + "listDirObjects");
	//
	// // 1.检索分布式缓存，判断容器名是否存在，直接到4
	//
	// // 2.如果不存在，检查Container的格式是否正确
	//
	// // 备注：检查数据库时，如果容器状态不是正常状态(如迁移中，删除中)，不允许获取数据。
	//
	// // 3.如果不正确直接返回错误
	//
	// // 4.如果容器名格式正确, 查询File表
	//
	// // 5.存在数据库错误，返回 NO DATA，系统记录错误日志。
	//
	// // 6.如果数据库操作正确，返回列表。
	//
	// throw new UnsupportedOperationException(
	// "ContainerResource::listDirObjects()");
	// }
	//
	// /*********************** 扩展：公共文件访问服务 ************************/
	//
	// /**
	// * 获取指定容器下的公共访问文件：GET /Container?marker=value2&maxresults=value3 HTTP/1.1
	// *
	// * @param name
	// * @param prefix
	// * @param marker
	// * @param maxresults
	// * @return
	// */
	// @GET
	// @HeaderParam(Headers.CDMI_PUBLIC_PREFIX)
	// @Produces("application/xml")
	// public Response listPublicObjects(@PathParam("container") String name,
	// @HeaderParam(Headers.CDMI_PUBLIC_PREFIX) String prefix,
	// @QueryParam(QueryParameters.MARKER) int marker,
	// @QueryParam(QueryParameters.MAXRESULTS) int maxresults) {
	//
	// System.out.println("invoke::" + "listPublicObjects");
	//
	// // 1.检索分布式缓存，判断容器名是否存在，直接到4
	//
	// // 2.如果不存在，检查Container的格式是否正确
	//
	// // 备注：检查数据库时，如果容器状态不是正常状态(如迁移中，删除中)，不允许获取数据。
	//
	// // 3.如果不正确直接返回错误
	//
	// // 4.如果容器名格式正确, 查询Pulic表
	//
	// // 5.存在数据库错误，返回 NO DATA，系统记录错误日志。
	//
	// // 6.如果数据库操作正确，返回列表。
	// throw new UnsupportedOperationException(
	// "ContainerResource::listPublicObjects()");
	// }
	//
	// /*********************** 扩展：文件外链服务 ************************/
	//
	// /**
	// * 获取指定目录下的外链对象：GET /Container?marker=value2&maxresults=value3 HTTP/1.1
	// *
	// * @param name
	// * @param path
	// * @param marker
	// * @param maxresults
	// * @return
	// */
	// @GET
	// @HeaderParam(Headers.CDMI_LINK_DIR)
	// @Produces("application/xml")
	// public Response listLinkObjects(@PathParam("container") String name,
	// @HeaderParam(Headers.CDMI_LINK_DIR) String path,
	// @QueryParam(QueryParameters.MARKER) int marker,
	// @QueryParam(QueryParameters.MAXRESULTS) int maxresults) {
	//
	// System.out.println("invoke::" + "listLinkObjects");
	// // 1.检索分布式缓存，判断容器名是否存在，直接到4
	//
	// // 2.如果不存在，检查Container的格式是否正确
	//
	// // 备注：检查数据库时，如果容器状态不是正常状态(如迁移中，删除中)，不允许获取数据。
	//
	// // 3.如果不正确直接返回错误
	//
	// // 4.如果容器名格式正确, 查询LINK表
	//
	// // 5.存在数据库错误，返回 NO DATA，系统记录错误日志。
	//
	// // 6.如果数据库操作正确，返回列表。
	// throw new UnsupportedOperationException(
	// "ContainerResource::listLinkObjects()");
	// }
	//
	// /**
	// * 允许容器下对象被指定网站外链访问：PUT /mycontainer/?link HTTP/1.1
	// *
	// * @param name
	// * @param path
	// * @param sites
	// * @return
	// */
	// @PUT
	// @HeaderParam(Headers.CDMI_LINK_PATH)
	// @Produces("application/xml")
	// public Response setLink4Objects(@PathParam("container") String name,
	// @HeaderParam(Headers.CDMI_LINK_PATH) String path,
	// Map<String, String> sites) {
	//
	// System.out.println("invoke::" + "setLink4Objects");
	//
	// // 1.检索分布式缓存，判断容器名是否存在，直接到4
	//
	// // 2.如果不存在，检查Container的格式是否正确
	//
	// // 备注：检查数据库时，如果容器状态不是正常状态(如迁移中，删除中)，不允许获取数据。
	//
	// // 3.如果不正确直接返回错误
	//
	// // 4.如果容器名格式正确, 插入记录到LINK表
	//
	// // 5.存在数据库错误，返回 失败，系统记录错误日志。
	//
	// // 6.如果数据库操作正确，返回成功。
	// throw new UnsupportedOperationException(
	// "ContainerResource::setLink4Objects()");
	// }
	//
	// /**
	// * 取消容器下对象的外链授权：Delete /mycontainer?link HTTP/1.1
	// *
	// * @param name
	// * @param path
	// * @return
	// */
	// @DELETE
	// @HeaderParam(Headers.CDMI_LINK_PATH)
	// @Produces("application/xml")
	// public Response cancelLinkObjects(@PathParam("container") String name,
	// @HeaderParam(Headers.CDMI_LINK_PATH) String path) {
	//
	// System.out.println("invoke::" + "cancelLinkObjects");
	//
	// // 1.检索分布式缓存，判断容器名是否存在，直接到4
	//
	// // 2.如果不存在，检查Container的格式是否正确
	//
	// // 备注：检查数据库时，如果容器状态不是正常状态(如迁移中，删除中)，不允许获取数据。
	//
	// // 3.如果不正确直接返回错误
	//
	// // 4.如果容器名格式正确, 直接从数据库LINK表中删除记录
	//
	// // 5.存在数据库错误，返回 失败，系统记录错误日志。
	//
	// // 6.如果数据库操作正确，返回成功。
	//
	// throw new UnsupportedOperationException(
	// "ContainerResource::cancelLinkObjects()");
	// }
	//
	// /*********************** 扩展数据服务：全文检索 ************************/
	//
	// /**
	// * 全文检索：GET /mycontainer?marker=value2&maxresults=value3 HTTP/1.1
	// *
	// * @param name
	// * @param path
	// * @param marker
	// * @param maxresults
	// * @return
	// */
	// @GET
	// @HeaderParam(Headers.CDMI_SEARCH_PATH)
	// @Produces("application/xml")
	// public Response contentSearch(@PathParam("container") String name,
	// @HeaderParam(Headers.CDMI_SEARCH_PATH) String path,
	// @HeaderParam(Headers.CDMI_SEARCH_KEYWORD) String keyword,
	// @HeaderParam(Headers.CDMI_SEARCH_FILETYPE) String filetype,
	// @HeaderParam(Headers.CDMI_SEARCH_SUMMARY_COLOR) String color,
	// @HeaderParam(Headers.CDMI_SEARCH_BEGIN_DATE) Date begindate,
	// @HeaderParam(Headers.CDMI_SEARCH_END_DATE) Date enddate,
	// @QueryParam(QueryParameters.MARKER) int marker,
	// @QueryParam(QueryParameters.MAXRESULTS) int maxresults) {
	//
	// System.out.println("invoke::" + "contentSearch");
	//
	// // 1.检索分布式缓存，判断容器名是否存在，直接到4
	//
	// // 2.如果不存在，检查Container的格式是否正确
	//
	// // 备注：检查数据库时，如果容器状态不是正常状态(如迁移中，删除中)，不允许获取数据。
	//
	// // 3.如果不正确直接返回错误
	//
	// // 4.如果容器名格式正确, 利用Java Feture类调用搜索引擎接口，进行分布式搜索。
	//
	// // 5.对搜索结果进行汇合，返回数据。
	//
	// throw new UnsupportedOperationException(
	// "ContainerResource::contentSearch()");
	// }
	//
	// /*********************** 其他：获取容器下的任务状态 ************************/
	//
	// /**
	// * 获取容器下的任务状态：GET /mycontainer?task HTTP/1.1
	// *
	// * @param name
	// * @param task
	// * FormatConverter/Download/Snapshot
	// * @param prefix
	// * @return
	// */
	//
	// @GET
	// @Produces(MediaTypes.TASK)
	// public Response listTask(@PathParam("container") String name,
	// @HeaderParam(Headers.CDMI_TASK_NAME) String task,
	// @HeaderParam(Headers.CDMI_TASK_PREFIX) String prefix) {
	//
	// System.out.println("invoke::" + "listTask");
	//
	// // 1.检索分布式缓存，判断容器名是否存在，直接到4
	//
	// // 2.如果不存在，检查Container的格式是否正确
	//
	// // 备注：检查数据库时，如果容器状态不是正常状态(如迁移中，删除中)，不允许获取数据。
	//
	// // 3.如果不正确直接返回错误
	//
	// // 4.如果容器名格式正确, 从TASK表中查询
	//
	// // 5.存在数据库错误，返回 失败，系统记录错误日志。
	//
	// // 6.如果数据库操作正确，返回成功。
	//
	// throw new UnsupportedOperationException("ContainerResource::listTask()");
	// }
}
